package com.netx.ebs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.netx.generics.basic.Checker;
import com.netx.generics.collections.ImmutableList;
import com.netx.generics.collections.ImmutableMap;
import com.netx.generics.sql.Column;
import com.netx.generics.sql.Table;
import com.netx.generics.time.Moment;
import com.netx.data.DatabaseException;
import com.netx.data.Field;
import com.netx.data.NoSuchInstanceException;
import com.netx.data.ValueList;
import com.netx.ebs.Transgression.TYPE;


public class Transgressions extends EbsEntity {

	public Transgressions() {
	}

	
	public ImmutableList<Transgression> find(long userID) throws DatabaseException {
		User user = Entities.getUsers(getConnection()).find(userID);
		if(user == null) {
			throw new NoSuchInstanceException("userID: "+userID);
		}
		else {
			Table data = getConnection().select("transgression_id, type, request_url, message, time_ocurred FROM transgressions WHERE user_id="+userID);
			List<Transgression> transgressions = new ArrayList<Transgression>();
			for(int i=0; i<data.getRowCount(); i++) {
				transgressions.add(new Transgression(data.getRow(i), user));
			}
			return new ImmutableList<Transgression>(transgressions);
		}
	}

	public ImmutableList<Transgression>[] getAllByUser() throws DatabaseException {
		return getAllByUser("username");
	}
	
	public ImmutableList<Transgression>[] getAllByUser(String orderField) throws DatabaseException {
		Checker.checkEmpty(orderField, "orderField");
		// Check whether the orderField exists:
		ImmutableMap<String,Field> fields = getMetaData().getFields();
		if(fields.get(orderField) == null) {
			throw new IllegalArgumentException("\""+orderField+"\" is not a valid field for entity \"users\"");
		}
		else {
			Table table = getConnection().select("user_id, "+orderField+" FROM users ORDERBY "+orderField);
			Column userIds = table.getColumn(1);
			List<ImmutableList<Transgression>> list = new ArrayList<ImmutableList<Transgression>>();
			for(int i=0; i<userIds.getRowCount(); i++) {
				ImmutableList<Transgression> transgressions = find(userIds.getLong(i));
				if(!transgressions.isEmpty()) {
					list.add(transgressions);
				}
			}
			@SuppressWarnings("unchecked")
			ImmutableList<Transgression>[] result = (ImmutableList<Transgression>[])list.toArray(new ImmutableList[0]);
			return result;
		}
	}

	public ImmutableList<Transgression> getAllByDate() throws DatabaseException {
		Table data = getConnection().select("transgression_id, type, request_url, message, time_ocurred FROM transgressions ORDERBY time_occurred");
		Users users = Entities.getUsers(getConnection());
		List<Transgression> transgressions = new ArrayList<Transgression>();
		Map<Long,User> userCache = new HashMap<Long,User>();
		for(int i=0; i<data.getRowCount(); i++) {
			long userId = data.getLong(8, i);
			// reuse already fetched users:
			User u = (User)userCache.get(new Long(userId));
			if(u == null) {
				u = users.find(userId);
				userCache.put(new Long(userId), u);
			}
			transgressions.add(new Transgression(data.getRow(i), u));
		}
		return new ImmutableList<Transgression>(transgressions);
	}

	public void remove(long transgressionID) throws DatabaseException {
		if(!exists(transgressionID)) {
			throw new NoSuchInstanceException("transgressionID: "+transgressionID);
		}
		else {
			delete(transgressionID);
		}
	}

	public boolean removeFor(long userID) throws DatabaseException {
		User user = Entities.getUsers(getConnection()).find(userID);
		if(user == null) {
			throw new NoSuchInstanceException("userID: "+userID);
		}
		else {
			return delete("user_id="+userID) != 0;
		}
	}
	
	// For ErrorHandlerServlet:
	long saveIllegalOperation(User u, char type, String requestURL, String message) throws DatabaseException {
		ValueList values = new ValueList();
		values.addValue("user_id", u==null ? null : new Long(u.getPrimaryKey()));
		values.addValue("type", type);
		values.addValue("request_url", requestURL);
		values.addValue("message", message);
		values.addValue("time_occurred", new Moment());
		return insert(values);
	}

	// For ErrorHandlerServlet:
	long saveIllegalAccess(long userId, Permission p, String requestURL) throws DatabaseException {
		return _save(userId, TYPE.ILLEGAL_ACCESS, p.getName(), requestURL);
	}
	
	// For ErrorHandlerServlet:
	long saveIllegalOperation(long userId, Throwable t, String requestURL) throws DatabaseException {
		return _save(userId, TYPE.ILLEGAL_OPERATION, t.getMessage(), requestURL);
	}

	private long _save(long userId, TYPE type, String message, String requestURL) throws DatabaseException {
		ValueList values = new ValueList();
		values.addValue("user_id", userId==0 ? null : new Long(userId));
		values.addValue("type", type == TYPE.ILLEGAL_ACCESS ? 'a' : 'o');
		values.addValue("request_url", requestURL);
		values.addValue("message", message);
		values.addValue("time_occurred", new Moment());
		return insert(values);
	}
}
